/**
 * Copyright (c) 2018 开源 All rights reserved.
 * <p>
 * https://www.sxyc.io
 * <p>
 * 版权所有，侵权必究！
 */

package io.renren.controller;

import cn.hutool.json.JSONUtil;
import com.wechat.pay.java.core.exception.ServiceException;
import com.wechat.pay.java.core.util.IOUtil;
import com.wechat.pay.java.service.payments.model.Transaction;
import io.renren.annotation.Login;
import io.renren.common.utils.Result;
import io.renren.modules.yckj.common.ThreadLocalUtil;
import io.renren.modules.yckj.common.service.JsapiPayService;
import io.renren.modules.yckj.common.service.PayData;
import io.renren.modules.yckj.common.service.PayResult;
import io.renren.modules.yckj.common.service.Resource;
import io.renren.modules.yckj.common.wx.JsapiType;
import io.renren.modules.yckj.dto.InvoiceLogsDTO;
import io.renren.modules.yckj.dto.OrderDTO;
import io.renren.modules.yckj.entity.InvoiceLogsEntity;
import io.renren.modules.yckj.enums.status.PayStatus;
import io.renren.modules.yckj.enums.type.BusinessType;
import io.renren.modules.yckj.service.InvoiceLogsService;
import io.renren.modules.yckj.service.OrderService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import lombok.AllArgsConstructor;
import org.springframework.web.bind.annotation.*;

import java.io.IOException;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.Map;

/**
 * 测试接口
 *
 * @author Mark sunlightcs@gmail.com
 */
@RestController
@RequestMapping("/yckj/pay")
@Tag(name = "支付接口")
@AllArgsConstructor
public class ApiPayController {
    private final JsapiPayService jsapiPayService;

    private final InvoiceLogsService invoiceLogsService;

    private final OrderService orderService;

    @Login
    @PostMapping("getUserRechargeParams")
    @Operation(summary = "获取用户充值参数:businessId传")
    public Result<Map<String, Object>> getUserRechargeParams(@RequestBody InvoiceLogsDTO invoiceLogsDTO) {
        invoiceLogsDTO.setBusinessId(ThreadLocalUtil.getUserId());
        return getRechargeParams(invoiceLogsDTO, BusinessType.RECHARGE_USER);
    }

    @Login
    @PostMapping("getTeamRechargeParams")
    @Operation(summary = "获取组充值参数:businessId必传")
    public Result<Map<String, Object>> getTeamRechargeParams(@RequestBody InvoiceLogsDTO invoiceLogsDTO) {
        return getRechargeParams(invoiceLogsDTO, BusinessType.RECHARGE_TEAM);
    }

    private Result<Map<String, Object>> getRechargeParams(@RequestBody InvoiceLogsDTO invoiceLogsDTO, BusinessType businessType) {
        invoiceLogsDTO.setUserId(ThreadLocalUtil.getUserId());
        invoiceLogsDTO.setUsername(ThreadLocalUtil.getUserName());
        invoiceLogsDTO.setBusinessType(businessType.getCode());
        invoiceLogsDTO.setCreateTime(new Date());
        invoiceLogsDTO.setUpdateTime(new Date());

        //保存业务数据
        boolean save = invoiceLogsService.save(invoiceLogsDTO);
        if (save) {
            //amount 转成分 获取参数
            String description = JsapiType.RECHARGE_USER.getName();
            if (invoiceLogsDTO.getBusinessType().equals(JsapiType.RECHARGE_TEAM.getCode()))
                description = JsapiType.RECHARGE_TEAM.getName();
            Map<String, Object> map = jsapiPayService.sign(ThreadLocalUtil.getOpenid(),
                    invoiceLogsDTO.getId(),
                    invoiceLogsDTO.getAmount().multiply(new BigDecimal(100)).intValue(),
                    invoiceLogsDTO.getBusinessType().toString(),
                    description);
            return new Result<Map<String, Object>>().ok(map);
        }
        return new Result<Map<String, Object>>().error("请求失败！");
    }

    @Login
    @PostMapping("getPayParams")
    @Operation(summary = "获取支付参数：businessId，businessType=2必传")
    public Result<Map<String, Object>> getPayParams(@RequestBody InvoiceLogsDTO invoiceLogsDTO) throws Exception {
        //保存业务数据
        OrderDTO orderDTO = orderService.get(invoiceLogsDTO.getBusinessId());
        if (orderDTO != null && orderDTO.getUserId().equals(ThreadLocalUtil.getUserId())) {
            invoiceLogsDTO.setUserId(ThreadLocalUtil.getUserId());
            invoiceLogsDTO.setUsername(ThreadLocalUtil.getUserName());
            invoiceLogsDTO.setCreateTime(new Date());
            invoiceLogsDTO.setUpdateTime(new Date());
            invoiceLogsDTO.setAmount(orderDTO.getActualAmount());
            invoiceLogsDTO.setBusinessType(BusinessType.PAY_ORDER.getCode());
            //判断数据库是否已有支付数据
            InvoiceLogsEntity dbInvoiceLogs = invoiceLogsService.getByUserIdBusiness(ThreadLocalUtil.getUserId(),
                    orderDTO.getId(),
                    BusinessType.PAY_ORDER.getCode());
            if (dbInvoiceLogs != null) {
                invoiceLogsDTO.setId(dbInvoiceLogs.getId());
                if (dbInvoiceLogs.getStatus().equals(PayStatus.PAYED.getCode())) {
                    return new Result<Map<String, Object>>().error("此订单已完成支付！");
                }
            } else {
                invoiceLogsService.save(invoiceLogsDTO);
            }
            try {
                //调用微信支付 amount 转成分
                Map<String, Object> map = jsapiPayService.sign(ThreadLocalUtil.getOpenid(),
                        invoiceLogsDTO.getId(),
                        orderDTO.getActualAmount().multiply(new BigDecimal(100)).intValue(),
                        JsapiType.PAY.getCode().toString(),
                        JsapiType.PAY.getName());
                return new Result<Map<String, Object>>().ok(map);
            } catch (ServiceException e) {
                if (e.getErrorCode().equals("ORDERPAID")) {
                    //已完成支付时处理业务逻辑
                    Transaction transaction = jsapiPayService.queryOrderByOutTradeNo(invoiceLogsDTO.getId().toString());
                    if (transaction != null && transaction.getTradeState().equals(Transaction.TradeStateEnum.SUCCESS)) {
                        invoiceLogsService.handleNotify(invoiceLogsDTO.getId().toString(),
                                transaction.getTransactionId(),
                                JSONUtil.toJsonStr(transaction));
                        return new Result<Map<String, Object>>().error("此订单已完成支付！");
                    }
                }
                System.out.println("payError" + e.getMessage());
            }
        }
        return new Result<Map<String, Object>>().error("请求失败！");
    }

    @PostMapping("notify")
    public String handleNotify(HttpServletRequest requst) throws Exception {
        try {
            // 1. 读取原始数据流
            String jsonResult = IOUtil.toString(requst.getInputStream());
            // 2. 签名验证与数据解析
            System.out.println("ld:" + jsonResult);
            PayResult payResult = JSONUtil.toBean(jsonResult, PayResult.class);
            if (payResult != null && payResult.getEvent_type().equals("TRANSACTION.SUCCESS")) {
                Resource resource = payResult.getResource();
                String jsonData = jsapiPayService.decryptToString(
                        resource.getAssociated_data().getBytes(StandardCharsets.UTF_8),
                        resource.getNonce().getBytes(StandardCharsets.UTF_8),
                        resource.getCiphertext());
                PayData payData = JSONUtil.toBean(jsonData, PayData.class);
                if (payData != null && payData.getTrade_state().equals("SUCCESS")) {
                    // 3. 业务处理
                    boolean processSuccess = invoiceLogsService.handleNotify(
                            payData.getOut_trade_no(), payData.getTransaction_id(), jsonData);
                    // 4. 构造响应
                    return processSuccess ? buildSuccessResponse() : buildFailResponse("业务处理失败");
                }
            }
            System.out.println("pay error:" + jsonResult);
            return buildFailResponse("支付失败");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    private String buildSuccessResponse() {
        return "<xml><return_code><![CDATA[SUCCESS]]></return_code>" + "<return_msg><![CDATA[OK]]></return_msg></xml>";
    }

    private String buildFailResponse(String msg) {
        return "<xml><return_code><![CDATA[FAIL]]></return_code>" + "<return_msg><![CDATA[" + msg + "]]></return_msg></xml>";
    }


    @PostMapping("queryOrderByOutTradeNo")
    @Operation(summary = "获取支付参数：outTradeNo必传")
    @Parameter(name = "outTradeNo", description = "业务号", required = true)
    public Result<Object> queryOrderByOutTradeNo(@RequestParam("outTradeNo") String outTradeNo) {
        Transaction transaction = jsapiPayService.queryOrderByOutTradeNo(outTradeNo);
        return new Result<Object>().ok(transaction);
    }

    @PostMapping("queryOrderById")
    @Operation(summary = "获取支付参数：orderId必传")
    @Parameter(name = "orderId", description = "微信订单号", required = true)
    public Result<Object> queryOrderById(@RequestParam("orderId") String orderId) {
        Transaction transaction = jsapiPayService.queryOrderById(orderId);
        return new Result<Object>().ok(transaction);
    }
}